package com.bayss.core.service.order;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bayss.core.DokoServerException;
import com.bayss.core.DokoServerExceptionFactor;
import com.bayss.core.entity.goods.Sku;
import com.bayss.core.entity.order.*;
import com.bayss.core.entity.order.mapper.OrderCommentMapper;
import com.bayss.core.entity.order.mapper.OrderGInfoMapper;
import com.bayss.core.entity.order.mapper.OrderMapper;
import com.bayss.core.entity.order.mapper.OrderRefundMapper;
import com.bayss.core.entity.pay.Pay;
import com.bayss.core.entity.station.Station;
import com.bayss.core.entity.user.UserInfo;
import com.bayss.core.enums.*;
import com.bayss.core.model.*;
import com.bayss.core.service.FoundService;
import com.bayss.core.service.GoodsService;
import com.bayss.core.service.TransactionRecordService;
import com.bayss.core.service.address.AddressService;
import com.bayss.core.service.coupon.CouponService;
import com.bayss.core.service.deliveryman.DeliverymanService;
import com.bayss.core.service.pay.PayService;
import com.bayss.core.service.station.StationService;
import com.bayss.core.service.user.UserService;
import com.bayss.core.util.FileUtil;
import com.bayss.core.util.OrderUtils;
import com.bayss.core.util.RedisUtil;
import com.bayss.core.util.SendSmsUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class OrderService {

    private static Logger logger = LogManager.getLogger();

    private final OrderMapper orderMapper;

    private final OrderCommentMapper orderCommentMapper;

    private final OrderRefundMapper orderRefundMapper;

    private final OrderGInfoMapper orderGInfoMapper;

    private final PayService payService;

    private final UserService userService;

    private final StationService stationService;

    private final AddressService addressService;

    private final GoodsService goodsService;

    private final CouponService couponService;

    private final DeliverymanService deliverymanService;
    private final TransactionRecordService transactionRecordService;
    private final static long timeArea = 1000 * 60 * 60 * 3;

    private final static long PAY_TIME_OUT = 1000 * 15 * 60;
    private final FoundService foundService;
    @Autowired
    RedisUtil redisUtil;

    public OrderService(OrderMapper orderMapper, OrderCommentMapper orderCommentMapper,
                        OrderGInfoMapper orderGInfoMapper, AddressService addressService,
                        PayService payService, StationService stationService, UserService userService,
                        GoodsService goodsService, CouponService couponService,
                        DeliverymanService deliverymanService, OrderRefundMapper orderRefundMapper,FoundService foundService,
                        TransactionRecordService transactionRecordService) {
        this.orderMapper = orderMapper;
        this.orderCommentMapper = orderCommentMapper;
        this.orderGInfoMapper = orderGInfoMapper;
        this.payService = payService;
        this.stationService = stationService;
        this.userService = userService;
        this.addressService = addressService;
        this.goodsService = goodsService;
        this.couponService = couponService;
        this.deliverymanService = deliverymanService;
        this.orderRefundMapper = orderRefundMapper;
        this.foundService = foundService;
        this.transactionRecordService = transactionRecordService;
    }

    /**
     * 创建订单
     */
    @Transactional
    public Map<String, Object> createOrder(Order order, List<ParamGInfo> paramGInfos, String openId, Integer isAtOnce, String code) {
        Map<String, Object> resMap = new HashMap<>();
        Station station = stationService.get(order.getStationId());

        LocalDate currentDate = LocalDate.now();
        String str = currentDate.toString();
        String openTime = str + " " + station.getOpenStartTime();
        String endTime = str + " " + station.getOrderEndTime();
        try {
            long start = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(openTime).getTime();
            long end = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTime).getTime();
            if (start > System.currentTimeMillis() || end < System.currentTimeMillis()) {
                throw new DokoServerException(DokoServerExceptionFactor.STATION_TIME_OUT);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

        String payInfo;
        String orderNo;
        String payPrice;
        if (paramGInfos.size() == 1) { // 区分是否是预订单， 多个单子进行拆单
            String number = OrderUtils.getOrderNo(OrderType.values()[order.getOrderType()], order.getUid(), "", false);
            Map<String, Long> costMap = stationService.costTime(order.getAddrId(), order.getStationId());
            long cost = costMap.get("sum_time") * 60 * 1000;
            long doTime = costMap.get("do_time") * 60 * 1000;
            long sendedTime = System.currentTimeMillis() + cost;
            if (isAtOnce == 0 && paramGInfos.get(0).getSendTime() > sendedTime) {
                sendedTime = paramGInfos.get(0).getSendTime();
            }
            String res = buildOrder(number, order, paramGInfos.get(0).getOrderGInfos(), sendedTime, System.currentTimeMillis() + doTime);
            orderNo = res.split("-")[0];
            payPrice = res.split("-")[1];
            resMap.put("orderNos", Arrays.asList(orderNo));
        } else {
            String pOrderNo = OrderUtils.getOrderNo(OrderType.values()[order.getOrderType()], order.getUid(), "", true);

            // 子单加入
            int sumPrice = 0;
            long currentTimeMillis = System.currentTimeMillis();
            List<String> orderNos = new ArrayList<>();
            for (ParamGInfo paramGInfo : paramGInfos) {
                order.setPOrderNo(pOrderNo);
                currentTimeMillis += 5000;
                SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
                long sendedTime = paramGInfo.getSendTime();
                String sonNo = OrderUtils.getOrderNo(OrderType.values()[order.getOrderType()], order.getUid(), df.format(new Date(currentTimeMillis)), false);
                String res = buildOrder(sonNo, order, paramGInfo.getOrderGInfos(), sendedTime, sendedTime - 2 * 60 * 60 * 1000);
                String price = res.split("-")[1];
                sumPrice += Integer.parseInt(price);
                orderNos.add(sonNo);
            }

            order.setOrderNo(pOrderNo);
            order.setOrderStatus(HandleCode.INIT.ordinal());
            int prePrice = 0;
            if (order.getPreId() != null) {
                prePrice = couponService.afterCouponPrice(sumPrice, order.getUid(), order.getPreId());
            }
            sumPrice -= prePrice;
            order.setTotlePrice(sumPrice);
            order.setPrePrice(prePrice);
            order.setPOrderNo("0");
            Date date = new Date();
            order.setStartTime(date);
            order.setSendTime(date);
            orderMapper.insertSelective(order);

            payPrice = sumPrice + "";
            orderNo = pOrderNo;
            resMap.put("pOrderNos", pOrderNo);
            resMap.put("orderNos", orderNos);
        }


        ChannelType channelType = ChannelType.values()[order.getChannel()];
        PayOrigin payOrigin = PayOrigin.O_CASH;
        if (channelType == ChannelType.CASH) {
            payOrigin = PayOrigin.O_CASH;
        } else if (channelType == ChannelType.MEMBER) {
            payOrigin = PayOrigin.O_MEMBER;
        } else if (channelType == ChannelType.WX) {
            payOrigin = PayOrigin.O_WX;
        }
        try {
            payInfo = payService.payOrder(openId, orderNo, order.getUid(), payPrice, payOrigin, code);
        } catch (Exception e) {
            throw new DokoServerException(DokoServerExceptionFactor.PAY_FAIL);
        }
        resMap.put("payInfo", payInfo);
        return resMap;
    }

    /**
     * 计算订单需要价格
     */
    public JSONObject costPrice(List<ParamGInfo> paramGInfos, Long stationId,
                                Long addrId, Integer orderMod, Integer orderType, Long preId, Long userId) {
        JSONArray jsonArray = new JSONArray();
        int sumPrice = 0;
        for (ParamGInfo paramGInfo : paramGInfos) {
            Map<String, Integer> map = paramGInfo.getOrderGInfos().stream().
                    collect(Collectors.toMap(OrderGInfo::getSkuCode, OrderGInfo::getgCount, (k1, k2) -> k1));
            SkuCost skuCost = goodsService.cost(map);
            if (orderType == 3) {
                skuCost.setSendPrice(0);
            } else {
                if (addrId != null && addrId != 0 && stationId != 0) {
                    skuCost.setSendPrice(stationService.costPrice(addrId, stationId));
                } else {
                    skuCost.setSendPrice(0);
                }
            }
            jsonArray.add(skuCost);
            sumPrice = sumPrice + skuCost.getTotalPrice() + skuCost.getSendPrice();
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("coupons", couponService.findByUserId(userId, sumPrice));
        int couponPrice = 0;
        if (preId != null && preId != 0) {
            couponPrice = couponService.afterCouponPrice(sumPrice, userId, preId);
            sumPrice -= couponPrice;
        }

        jsonObject.put("sumPrice", sumPrice);
        jsonObject.put("prePrice", couponPrice);
        jsonObject.put("priceDesc", jsonArray);
        return jsonObject;
    }

    /**
     * 获取订单（用户侧）
     */
    public List<ShowOrder> getOrders(Long uid, Long maxId, Integer count, Integer tab) {
        OrderExample orderExample = new OrderExample();
        orderExample.setOrderByClause("id desc limit " + count);
        OrderExample.Criteria criteria = orderExample.createCriteria();
        criteria.andUidEqualTo(uid);
        criteria.andPOrderNoNotEqualTo("0");
        criteria.andOrderStatusNotEqualTo(HandleCode.INVALID.ordinal());
        criteria.andIdLessThan(maxId == 0 ? Integer.MAX_VALUE : maxId);
        if (tab == 2) {
            criteria.andOrderStatusIn(Arrays.asList(HandleCode.SENDED.ordinal()));
        }

        if (tab == 3) {
            criteria.andOrderStatusIn(Arrays.asList(HandleCode.CANCEL.ordinal()));
        }

        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (CollectionUtils.isEmpty(orders)) {
            return new ArrayList<>();
        }

        return orders.stream()
                .map(this::buildOrderInfo)
                .collect(Collectors.toList());
    }

    /**
     * 骑手获取订单
     */
    public List<ShowOrder> getDeliverymanOrders(Long deliverymanId, Long maxId, Integer count, Integer isFinish) {
        OrderExample orderExample = new OrderExample();
        orderExample.setOrderByClause("id desc limit " + count);
        OrderExample.Criteria criteria = orderExample.createCriteria();
        criteria.andHidEqualTo(deliverymanId.intValue());
        criteria.andPOrderNoNotEqualTo("0");
        if (isFinish == 0) {
            criteria.andOrderStatusIn(Arrays.asList(HandleCode.TRANWAIT.ordinal(), HandleCode.SENDWAIT.ordinal(), HandleCode.SENDING.ordinal()));
        } else {
            criteria.andOrderStatusIn(Arrays.asList(HandleCode.SENDED.ordinal(), HandleCode.COMMENTED.ordinal()));
        }

        if (maxId != 0) {
            criteria.andIdLessThan(maxId);
        }

        List<Order> orders = orderMapper.selectByExample(orderExample);
        return orders == null ? new ArrayList<>() : orders.stream()
                .map(this::buildOrderInfo)
                .collect(Collectors.toList());
    }

    /**
     * 下单时构建订单
     */
    private String buildOrder(String orderNo, Order order, List<OrderGInfo> orderGInfos, long time, long goodFinishTime) {
        Map<String, Integer> map = orderGInfos.stream().collect(Collectors.toMap(OrderGInfo::getSkuCode, OrderGInfo::getgCount, (k1, k2) -> k1));
        SkuCost skuCost = goodsService.cost(map);
        int totlePrice = skuCost.getTotalPrice();

        order.setOrderNo(orderNo);
        order.setOrderStatus(HandleCode.INIT.ordinal());
        // 计算 订单价格 && 配送费
        int sendPrice = 0;
        if (order.getOrderType() == 3) {
            order.setRevcCode(OrderUtils.getRecvNo());
        } else {
            sendPrice = stationService.costPrice(order.getAddrId(), order.getStationId());
        }
        order.setSendPrice(sendPrice);
        totlePrice += sendPrice;
        order.setTotlePrice(totlePrice);

        if (StringUtils.isBlank(order.getPOrderNo())) {
            int prePrice = 0;
            if (order.getPreId() != null) {
                prePrice = couponService.afterCouponPrice(totlePrice, order.getUid(), order.getPreId());
            }
            order.setTotlePrice(totlePrice - prePrice);
            order.setPrePrice(prePrice);
        }

        Date date = new Date(time);
        order.setSendTime(date);
        order.setStartTime(new Date());
        order.setGoodFinishTime(new Date(goodFinishTime));

        boolean res;
        try {
            res = orderMapper.insertSelective(order) > 0;
        } catch (Exception e) {
            logger.error("order insert error order no is " + orderNo, e);
            throw new DokoServerException(DokoServerExceptionFactor.CREATE_ORDER_FAIL);
        }

        if (!res) {
            // TODO  加入预警，重试等逻辑
            logger.warn("create order is fail");
            throw new DokoServerException(DokoServerExceptionFactor.CREATE_ORDER_FAIL);
        }

        Map<String, Integer> skuPriceMap = skuCost.getSkuPriceMaps();
        Map<String, Integer> boxPriceMap = skuCost.getBoxPriceMaps();
        for (OrderGInfo orderGInfo : orderGInfos) {
            orderGInfo.setOrderNo(orderNo);
            orderGInfo.setgSumPrice(skuPriceMap.get(orderGInfo.getSkuCode()));
            orderGInfo.setBoxPrice(boxPriceMap.get(orderGInfo.getSkuCode()));

            boolean gRes = false;
            try {
                gRes = orderGInfoMapper.insertSelective(orderGInfo) > 0;
            } catch (Exception e) {
                logger.error("order_g_info insert error order no is " + orderNo + " sku code is " + orderGInfo.getSkuCode(), e);
            }
            if (!gRes) {
                // TODO  加入预警，重试等逻辑
            }
        }
        return orderNo + "-" + order.getTotlePrice();
    }

    /**
     * 处理订单订单
     */
    public OrderMsg<String> handlerOrder(OrderOp orderOp, ProcessInfo processInfo) {
        OrderMsg<String> orderMsg = new OrderMsg<>();
        try {
            switch (orderOp) {
                case ORDER_REVC: // 商家确认接单
                    orderMsg.setOk(revcOrder(processInfo));
                    break;
                case ORDER_TRAN: // 派单
                    orderMsg.setOk(tranOrder(processInfo));
                    break;
                case ORDER_SEND_WAIT: // 确认接收配送单
                    orderMsg.setOk(sendWaitOrder(processInfo));
                    break;
                case ORDER_SENDING: // 确认取餐，配送中
                    orderMsg.setOk(sendingOrder(processInfo));
                    break;
                case ORDER_SENDED: // 确认送达
                    orderMsg.setOk(sendedOrder(processInfo));
                    break;
            }
        } catch (Exception e) {
            logger.error("handler is error orderOp is %s order_no is %s" + orderOp.name(), processInfo.getOrderNo());
        }
        return orderMsg;
    }

    /**
     * 确认支付
     */
    @Transactional
    public boolean payAckOrder(ProcessInfo processInfo) {
        String orderNo = processInfo.getOrderNo();
        boolean res;
        if (orderNo.startsWith("x")) {
            res = orderMapper.ackPayOrders(processInfo.getOrderNo()) > 0;
        } else {
            res = orderMapper.ackPayOrder(processInfo.getOrderNo()) > 0;
        }
        if (res) {
            payService.ackPay(processInfo.getOrderNo());
        }

        //交易记录
        Order order = getOrder(orderNo);
        transactionRecordService.saveOrderRecord(order.getUid(),order.getTotlePrice(),orderNo);

        if (order.getPreId() != null) {
            boolean r = couponService.useCouponUid(order.getPreId(), order.getUid());
            logger.info("修改券完成:{}", r);
        }
        return res;
    }

    // 接收订单
    private boolean revcOrder(ProcessInfo processInfo) {
        // 修改订单状态
        int res;
        Order order = getOrder(processInfo.getOrderNo());
        if (order == null) {
            return false;
        }
        OrderType orderType = OrderType.values()[order.getOrderType()];
        if (orderType == OrderType.CASH || orderType == OrderType.COMMON) {
            res = orderMapper.revcOrder(processInfo.getOrderNo(), HandleCode.TRANIING.ordinal(), null);
        } else if (orderType == OrderType.SELF) {
            // 生成取餐码
            String revcCode = "";
            res = orderMapper.revcOrder(processInfo.getOrderNo(), HandleCode.SELFTAKING.ordinal(), revcCode);
        } else {
            res = 0;
        }
        return res > 0;
    }

    // 派单
    private boolean tranOrder(ProcessInfo processInfo) {
        // 修改订单状态与骑手id
        int res = orderMapper.tranOrder(processInfo.getHid(), processInfo.getOrderNo());
        return res > 0;
    }

    // 骑手确认接收订单, 等待取餐
    private boolean sendWaitOrder(ProcessInfo processInfo) {
        // 骑手确认接收订单, 等待取餐
        int res = orderMapper.sendWait(processInfo.getOrderNo());
        return res > 0;
    }

    // 骑手取到餐，正在配送
    private boolean sendingOrder(ProcessInfo processInfo) {
        int res = orderMapper.sending(processInfo.getOrderNo());
        return res > 0;
    }

    // 确认送达
    private boolean sendedOrder(ProcessInfo processInfo) {
        Order order = getOrder(processInfo.getOrderNo());
        if (order == null) {
            return false;
        }
        int res;
        OrderType orderType = OrderType.values()[order.getOrderType()];
        if (orderType == OrderType.CASH || orderType == OrderType.COMMON) {
            // 骑手确认送达
            Order order1 = Order.builder()
                    .orderStatus(HandleCode.SENDED.ordinal())
                    .endTime(new Date())
                    .build();
            OrderExample orderExample = new OrderExample();
            OrderExample.Criteria criteria = orderExample.createCriteria();
            criteria.andOrderStatusEqualTo(HandleCode.SENDING.ordinal());
            criteria.andOrderNoEqualTo(processInfo.getOrderNo());
            res = orderMapper.updateByExampleSelective(order1, orderExample);
        } else if (orderType == OrderType.SELF) {
            // 店家确认客户取餐
            res = orderMapper.sendedByRevcNo(processInfo.getRevcCode());
        } else {
            res = 0;
        }
        return res > 0;
    }

    // 自取单，店家确认完成
    private boolean ackShopOrder(ProcessInfo processInfo) {

        int res = orderMapper.ackShop(processInfo.getOrderNo());
        return res > 0;
    }

    /**
     * 评论
     */
    public boolean comment(OrderComment orderComment) {
        OrderCommentExample orderCommentExample = new OrderCommentExample();
        OrderCommentExample.Criteria criteria = orderCommentExample.createCriteria();
        criteria.andOrderNoEqualTo(orderComment.getOrderNo());
        criteria.andUidEqualTo(orderComment.getUid());
        List<OrderComment> orderComments = orderCommentMapper.selectByExample(orderCommentExample);
        if (!CollectionUtils.isEmpty(orderComments)) {
            throw new DokoServerException(DokoServerExceptionFactor.PARAM_VERIFY_FAIL, "uid comment already");
        }

        // 商铺评价同步到留言列表
        foundService.addFoundMessageFromOrder(orderComment);

        orderComment.setStatus(0);
        orderComment.setDisplay(0);
        Order order = getOrder(orderComment.getOrderNo());
        orderComment.setStationId(order.getStationId());
        boolean res = orderCommentMapper.insertSelective(orderComment) > 0;
        if (res) {
            return orderMapper.commented(orderComment.getOrderNo()) > 0;
        }
        return false;
    }

    /**
     * 退款
     */
    public boolean refund(OrderRefund orderRefund) {
        String urls = orderRefund.getRefundUrl();
        if (StringUtils.isNotBlank(urls)) {
            String[] us = urls.split(",");
            String resUrls = Stream.of(us).map(FileUtil::formatImgUrl).collect(Collectors.joining(","));
            orderRefund.setRefundUrl(resUrls);
        }

        String skuStr = orderRefund.getRefundSkus();
        if (goodsService.checkSkuExist(skuStr)) {
            throw new DokoServerException(DokoServerExceptionFactor.PARAM_VERIFY_FAIL, "sku code is not exist");
        }

        boolean res = orderRefundMapper.insertSelective(orderRefund) > 0;
        if (res) {
            return orderMapper.cancel(orderRefund.getOrderNo()) > 0;
        }
        return false;
    }

    /**
     * 退款审核
     */
    public boolean refundCheck(String orderNo, int op, int opId, String opName, int money) {
        OrderRefundExample orderRefundExample = new OrderRefundExample();
        OrderRefundExample.Criteria criteria = orderRefundExample.createCriteria();
        criteria.andOrderNoEqualTo(orderNo);
        List<OrderRefund> orderRefunds = orderRefundMapper.selectByExample(orderRefundExample);
        if (orderRefunds.size() == 0) {
            return false;
        }
        for (OrderRefund orderRefund : orderRefunds) {
            orderRefund.setRefundStatus(op);
            orderRefund.setOpId(opId);
            orderRefund.setOpName(opName);
            orderRefund.setRefundMoney(money);
            orderRefundMapper.updateByPrimaryKey(orderRefund);
        }

        Order order;
        if (op == 1) {
            order = Order.builder().orderStatus(HandleCode.REFUNDED.ordinal()).build();
        } else {
            order = Order.builder().orderStatus(HandleCode.REFUNDREJECT.ordinal()).build();
        }
        OrderExample orderExample = new OrderExample();
        OrderExample.Criteria ordeCriteria = orderExample.createCriteria();
        ordeCriteria.andOrderNoEqualTo(orderNo);
        ordeCriteria.andOrderStatusEqualTo(HandleCode.CANCEL.ordinal());
        return orderMapper.updateByExampleSelective(order, orderExample) > 0;
    }

    public Order getOrder(String orderNo) {
        OrderExample orderExample = new OrderExample();
        orderExample.createCriteria().andOrderNoEqualTo(orderNo);
        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (CollectionUtils.isEmpty(orders)) {
            return null;
        }

        return orders.get(0);
    }

    /**
     * 获取订单详情
     */
    public ShowOrder getOrderDesc(String orderNo) {
        Order order = getOrder(orderNo);
        if (order == null) {
            throw new DokoServerException(DokoServerExceptionFactor.PARAM_VERIFY_FAIL, "order no is not exist");
        }
        return buildOrderInfo(order);
    }

    /**
     * 获取订单详情
     */
    public boolean orderCancel(String orderNo) {
        Order order = Order.builder()
                .orderStatus(HandleCode.INVALID.ordinal())
                .build();
        OrderExample orderExample = new OrderExample();
        OrderExample.Criteria criteria = orderExample.createCriteria();
        criteria.andOrderNoEqualTo(orderNo);
        criteria.andOrderStatusEqualTo(HandleCode.INIT.ordinal());
        return orderMapper.updateByExampleSelective(order, orderExample) > 0;
    }

    /**
     * 订单支付
     */
    public String orderPay(String orderNo) {
        OrderExample orderExample = new OrderExample();
        OrderExample.Criteria criteria = orderExample.createCriteria();
        criteria.andOrderNoEqualTo(orderNo);
        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (CollectionUtils.isEmpty(orders)) {
            throw new DokoServerException(DokoServerExceptionFactor.DEFAULT, "order is not exist");
        }

        Order order = orders.get(0);
        if (StringUtils.isNotBlank(order.getPOrderNo())) {
            orderNo = order.getPOrderNo();
        }
        if (System.currentTimeMillis() - order.getStartTime().getTime() > PAY_TIME_OUT) {
            throw new DokoServerException(DokoServerExceptionFactor.ORDER_PAY_TIME_OUT);
        }
        Pay pay = payService.getPay(orderNo);
        return pay.getPayInfo();
    }

    public boolean orderSms(long uid, String tel){
        String sendTel = "";
        int code = (int)((Math.random()*9+1)*100000);
        if (StringUtils.isNotBlank(tel)) {
            sendTel = tel;
        } else {
            UserInfo userInfo = userService.getUser(uid);
            if (userInfo.getType() == 1) {
                throw new DokoServerException(DokoServerExceptionFactor.SEND_SMS_FAIL, "user is not ");
            }
            if (StringUtils.isBlank(userInfo.getCellphone())) {
                throw new DokoServerException(DokoServerExceptionFactor.SEND_SMS_FAIL, "user phone no is exist");
            }
            sendTel = userInfo.getCellphone();
        }
        boolean res = redisUtil.set(uid+"-"+code, 1, 60*5);
        if (res) {
            return SendSmsUtil.sendVailCode(sendTel, code+"");
        }
        return false;
    }

    /**
     * 后台查询订单
     */
    public PageInfo<ShowOrder> getOrderByPage(String orderNo, String userName, Long stationId, Integer orderType,
                                              Integer channel, Integer orderStatus,
                                              Long startTime, Long endTime, Integer page, Integer pageSize) {
        OrderExample orderExample = new OrderExample();
        orderExample.setOrderByClause("start_time desc");
        OrderExample.Criteria criteria = orderExample.createCriteria();
        if (StringUtils.isNotBlank(orderNo)) {
            criteria.andOrderNoLike(orderNo);
        }
        if (stationId != null && stationId != 0) {
            criteria.andStationIdEqualTo(stationId);
        }
        if (orderType != null && orderType != 0) {
            criteria.andOrderTypeEqualTo(orderType);
        }
        if (channel != null && channel != 0) {
            criteria.andChannelEqualTo(channel);
        }
        if (startTime != null && startTime != 0) {
            criteria.andStartTimeGreaterThanOrEqualTo(new Date(startTime));
        }
        if (endTime != null && endTime != 0) {
            criteria.andStartTimeLessThanOrEqualTo(new Date(endTime));
        }
        if (StringUtils.isNotBlank(userName)) {
            List<UserInfo> userInfos = userService.getUserByName(userName);
            if (userInfos != null && userInfos.size() > 0) {
                List<Long> ids = userInfos.stream().map(UserInfo::getId).collect(Collectors.toList());
                criteria.andUidIn(ids);
            }
        }
        if (orderStatus != null && orderStatus != 0) {
            criteria.andOrderStatusEqualTo(orderStatus);
        }
        PageHelper.startPage(page, pageSize);
        PageInfo pageInfo = PageHelper.startPage(page, pageSize).doSelectPageInfo(() -> orderMapper.selectByExample(orderExample));
        List<Order> orders = pageInfo.getList();
        List<ShowOrder> showOrders = orders.stream().map(this::buildOrderInfo).collect(Collectors.toList());
        pageInfo.setList(showOrders);
        return pageInfo;
    }

    /**
     * 订单池
     */
    public List<ShowOrder> getOrdersByPool(Long stationId, HandleCode handleCode, Long maxId, Integer count) {
        OrderExample orderExample = new OrderExample();
        orderExample.setOrderByClause("id asc limit " + count);
        OrderExample.Criteria criteria = orderExample.createCriteria();
        criteria.andStationIdEqualTo(stationId);
        criteria.andOrderStatusEqualTo(handleCode.ordinal());
        criteria.andPOrderNoNotEqualTo("0");
        criteria.andIdGreaterThan(maxId);
        List<Order> orders = orderMapper.selectByExample(orderExample);
        if (CollectionUtils.isEmpty(orders)) {
            return null;
        }
        return orders.stream().map(this::buildOrderInfo).collect(Collectors.toList());
    }

    /**
     * 商家拉取后上报确认
     */
    public boolean submit(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order.getOrderStatus() != HandleCode.NEW.ordinal()) {
            return true;
        }

        if (order.getOrderType() == 3) {
            order.setOrderStatus(HandleCode.SELFTAKING.ordinal());
        } else {
            order.setOrderStatus(HandleCode.TRANIING.ordinal());
        }
        return orderMapper.updateByPrimaryKey(order) > 0;
    }

    /**
     * 评论查询
     */
    public PageInfo<OrderComment> getComments(long stationId, int status, int display, int page, int pageSize) {
        OrderCommentExample orderCommentExample = new OrderCommentExample();
        orderCommentExample.setOrderByClause("id desc");
        OrderCommentExample.Criteria criteria = orderCommentExample.createCriteria();
        if (status != -1) {
            criteria.andStatusEqualTo(status);
        }
        if (display != -1) {
            criteria.andDisplayEqualTo(display);
        }
        if (stationId != -1) {
            criteria.andStationIdEqualTo(stationId);
        }
        PageHelper.startPage(page, pageSize);
        PageInfo pageInfo = PageHelper.startPage(page, pageSize).doSelectPageInfo(() -> orderCommentMapper.selectByExample(orderCommentExample));
        List<OrderComment> orderComments = pageInfo.getList();
        for (OrderComment orderComment : orderComments) {
            String gurl = orderComment.getGUrl();
            if (StringUtils.isNotBlank(gurl)) {
                String[] gurls = gurl.split(",");
                for (int i = 0; i < gurls.length; i++) {
                    gurls[i] = FileUtil.imgUrl(gurls[i]);
                }
                gurl = StringUtils.join(gurls, ",");
            }
            orderComment.setGUrl(gurl);
            UserInfo userInfo = userService.getUser(orderComment.getUid());
            orderComment.setUserInfo(userInfo);
        }
        return pageInfo;
    }

    /**
     * 评论设置
     */
    public boolean setComment(String orderNo, int status, int display) {
        OrderComment orderComment = OrderComment.builder()
                .status(status)
                .display(display)
                .build();
        OrderCommentExample orderCommentExample = new OrderCommentExample();
        OrderCommentExample.Criteria criteria = orderCommentExample.createCriteria();
        criteria.andOrderNoEqualTo(orderNo);
        return orderCommentMapper.updateByExampleSelective(orderComment, orderCommentExample) > 0;
    }

    /**
     * 组装订单详情
     */
    private ShowOrder buildOrderInfo(Order order) {
        OrderGInfoExample orderGInfoExample = new OrderGInfoExample();
        OrderGInfoExample.Criteria criteria1 = orderGInfoExample.createCriteria();
        criteria1.andOrderNoEqualTo(order.getOrderNo());
        List<OrderGInfo> orderGInfos = orderGInfoMapper.selectByExample(orderGInfoExample);
        AtomicInteger boxPrice = new AtomicInteger();
        List<ShowOrderGInfo> showOrderGInfos = orderGInfos.stream()
                .map(o -> {
                    Sku sku;
                    try {
                        sku = goodsService.getSkuDesc(o.getSkuCode());
                    } catch (Exception e) {
                        logger.error("buildOrderInfo is error sku code is " + o.getSkuCode(), e);
                        return null;
                    }

                    boxPrice.addAndGet(o.getBoxPrice());
                    return ShowOrderGInfo.builder()
                            .gCount(o.getgCount())
                            .gSumPrice(o.getgSumPrice())
                            .boxPrice(o.getBoxPrice())
                            .sku(sku)
                            .build();
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        String stationName = "";
        String stationPic = "";
        String stationTel = "";
        long stationId = order.getStationId();
        Station station = stationService.get(stationId);
        if (station != null) {
            stationName = station.getStationName();
            stationPic = station.getStationPic();
            stationTel = station.getStationCelliphone();
        }

        ShowOrderRefund showOrderRefund = null;
        if (order.getOrderStatus() == HandleCode.CANCEL.ordinal()) {
            OrderRefundExample orderRefundExample = new OrderRefundExample();
            OrderRefundExample.Criteria criteria = orderRefundExample.createCriteria();
            criteria.andOrderNoEqualTo(order.getOrderNo());
            List<OrderRefund> orderRefunds = orderRefundMapper.selectByExample(orderRefundExample);
            if (orderRefunds.size() > 0) {
                OrderRefund orderRefund = orderRefunds.get(0);
                List<OrderGInfo> orderGInfoList = JSONArray.parseArray(orderRefund.getRefundSkus(), OrderGInfo.class);
                List<ShowOrderGInfo> showOrderGInfoList = orderGInfoList.stream()
                        .map(o -> {
                            Sku sku;
                            try {
                                sku = goodsService.getSkuDesc(o.getSkuCode());
                            } catch (Exception ex) {
                                ex.printStackTrace();
                                return null;
                            }
                            return ShowOrderGInfo.builder()
                                    .gCount(o.getgCount())
                                    .gSumPrice(o.getgSumPrice())
                                    .boxPrice(o.getBoxPrice())
                                    .sku(sku)
                                    .build();
                        })
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());

                showOrderRefund = ShowOrderRefund.builder()
                        .orderNo(orderRefund.getOrderNo())
                        .refundDesc(orderRefund.getRefundDesc())
                        .refundResource(orderRefund.getRefundResource())
                        .refundSkus(orderRefund.getRefundSkus())
                        .refundStatus(orderRefund.getRefundStatus())
                        .refundUrl(FileUtil.imgUrl(orderRefund.getRefundUrl()))
                        .createTime(orderRefund.getCreateTime())
                        .id(orderRefund.getId())
                        .showOrderGInfos(showOrderGInfoList)
                        .build();
            }
        }

        Integer paySurplusTime = null;
        if (order.getOrderStatus() == HandleCode.INIT.ordinal()) {
            paySurplusTime = (int) (PAY_TIME_OUT - (System.currentTimeMillis() - order.getStartTime().getTime())) / 1000;
            if (paySurplusTime < 1) {
                if (orderCancel(order.getOrderNo())) {
                    order.setOrderStatus(HandleCode.INVALID.ordinal());
                }
            }
        }

        List<ShowOrder> showOrders = new ArrayList<>();
        if (order.getOrderNo().startsWith("x")) {
            OrderExample orderExample = new OrderExample();
            OrderExample.Criteria criteria = orderExample.createCriteria();
            criteria.andPOrderNoEqualTo(order.getOrderNo());
            List<Order> orders = orderMapper.selectByExample(orderExample);
            for (Order o : orders) {
                Order o1 = getOrder(o.getOrderNo());
                if (o1 != null) {
                    showOrders.add(buildOrderInfo(o1));
                }
            }
        }

        return ShowOrder.builder()
                .id(order.getId())
                .channel(order.getChannel())
                .orderDesc(order.getOrderDesc())
                .orderMod(order.getOrderMod())
                .orderType(order.getOrderType())
                .orderNo(order.getOrderNo())
                .stationId(stationId)
                .stationName(stationName)
                .stationPic(stationPic)
                .stationTel(stationTel)
                .orderStatus(order.getOrderStatus())
                .sendPrice(order.getSendPrice())
                .sendTime(order.getSendTime())
                .goodFinishTime(order.getGoodFinishTime())
                .totlePrice(order.getTotlePrice())
                .boxPrice(boxPrice.intValue())
                .prePrice(order.getPrePrice())
                .deliverymanInfo(deliverymanService.get(Long.valueOf(order.getHid())))
                .userInfo(userService.getUser(order.getUid()))
                .addressInfo(addressService.get(order.getAddrId()))
                .endTime(order.getEndTime())
                .startTime(order.getStartTime())
                .paySurplusTime(paySurplusTime)
                .showOrderGInfos(showOrderGInfos)
                .showOrderRefund(showOrderRefund)
                .showOrders(showOrders)
                .build();
    }

}
